#include <drivers/ps2_mouse.h>
#include <drivers/ps2_kbd.h>
#include <acpi/acpi.h>
#include <drivers/framebuffer.h>
#include <kprint.h>
#include <task/task.h>

mouse_dec ms_dec;
spinlock_t get_lock;
int32_t mouse_x = 0;
int32_t mouse_y = 0;

bool mousedecode(uint8_t data)
{
    cli();

    if (ms_dec.phase == 0)
    {
        if (data == 0xfa)
        {
            ms_dec.phase = 1;
        }

        sti();

        return false;
    }
    if (ms_dec.phase == 1)
    {
        if ((data & 0xc8) == 0x08)
        {
            ms_dec.buf[0] = data;
            ms_dec.phase = 2;
        }

        sti();

        return 0;
    }
    if (ms_dec.phase == 2)
    {
        ms_dec.buf[1] = data;
        ms_dec.phase = 3;
        return 0;
    }
    if (ms_dec.phase == 3)
    {
        ms_dec.buf[2] = data;
        ms_dec.phase = 1;
        ms_dec.btn = ms_dec.buf[0] & 0x07;
        ms_dec.x = ms_dec.buf[1];
        ms_dec.y = ms_dec.buf[2];

        if ((ms_dec.buf[0] & 0x10) != 0)
            ms_dec.x |= 0xffffff00;
        if ((ms_dec.buf[0] & 0x20) != 0)
            ms_dec.y |= 0xffffff00;
        ms_dec.y = -ms_dec.y;

        sti();

        return true;
    }

    sti();

    ms_dec.phase = 0;

    return false;
}

void mouse_handler(uint8_t irq, uint64_t param, struct pt_regs *regs)
{
    uint8_t data = io_in8(PORT_KB_DATA);

    if (mousedecode(data))
    {
        spin_lock(&get_lock);

        mouse_x += ms_dec.x;
        mouse_y += ms_dec.y;

        if (mouse_x < 0)
            mouse_x = 0;
        if (mouse_y < 0)
            mouse_y = 0;
        if (mouse_x > (int32_t)current_framebuffer->width - 1)
            mouse_x = (int32_t)current_framebuffer->width - 1;
        if (mouse_y > (int32_t)current_framebuffer->height - 1)
            mouse_y = (int32_t)current_framebuffer->height - 1;

        spin_unlock(&get_lock);

        if (ms_dec.btn & 0x01)
        {
            ms_dec.left = true;
        }
        else
        {
            ms_dec.left = false;
        }

        if (ms_dec.btn & 0x02)
        {
            ms_dec.right = true;
        }
        else
        {
            ms_dec.right = false;
        }

        if (ms_dec.btn & 0x04)
        {
            ms_dec.center = true;
        }
        else
        {
            ms_dec.center = false;
        }
    }
}

extern task_window_t *current_top_window;

void sys_get_mouse_xy(int32_t *x, int32_t *y)
{
    spin_lock(&get_lock);
    *x = (int32_t)mouse_x;
    *y = (int32_t)mouse_y;
    spin_unlock(&get_lock);
}

bool sys_mouse_click()
{
    return (ms_dec.left || ms_dec.right);
}

void mouse_install(uint8_t vector, uint32_t arg)
{
    ioapic_add(vector, 12);
}

hardware_intr_controller mouse_controller =
    {
        .install = mouse_install,
        .enable = ioapic_enable,
};

void mouse_init()
{
    irq_register(PS2_MOUSE_INTERRUPT_VECTOR, mouse_handler, 0, &mouse_controller, "PS2 MOUSE");

    // 启用鼠标端口
    wait_KB_write();
    io_out8(PORT_KB_CMD, KB_EN_MOUSE_INTFACE); // 0xA8

    // 发送鼠标启用命令
    wait_KB_write();
    io_out8(PORT_KB_CMD, KB_SEND2MOUSE); // 0xD4
    wait_KB_write();
    io_out8(PORT_KB_DATA, MOUSE_EN); // 0xF4

    // 必须等待ACK
    wait_KB_read();
    if (io_in8(PORT_KB_DATA) != 0xFA)
    {
        kerror("Mouse enable failed\n");
    }

    // 设置鼠标采样率为100 (可选，但推荐)
    wait_KB_write();
    io_out8(PORT_KB_CMD, KB_SEND2MOUSE);
    wait_KB_write();
    io_out8(PORT_KB_DATA, 0xF3); // 设置采样率
    wait_KB_read();
    if (io_in8(PORT_KB_DATA) != 0xFA)
    {
    }

    wait_KB_write();
    io_out8(PORT_KB_CMD, KB_SEND2MOUSE);
    wait_KB_write();
    io_out8(PORT_KB_DATA, 100); // 100 samples/s
    wait_KB_read();
    if (io_in8(PORT_KB_DATA) != 0xFA)
    {
    }

    spin_init(&get_lock);
    memset(&ms_dec, 0, sizeof(ms_dec));
}
